using System;
using OracleInternal.Common;
using OracleInternal.Secure.Network;

namespace OracleInternal.Network
{
	internal class WriterStream
	{
		protected SessionContext m_sessionCtx;

		internal DataPacket m_dataPacket;

		private byte[] m_oneByteBuffer = new byte[1];

		internal WriterStream(SessionContext sessCtx)
		{
			m_sessionCtx = sessCtx;
			m_dataPacket = new DataPacket(sessCtx);
		}

		internal void Write(OraBuf OB)
		{
			if (m_sessionCtx.m_onBreakReset)
			{
				throw new NetworkException(3111);
			}
			if (!m_sessionCtx.isNTConnected)
			{
				throw new NetworkException(12614);
			}
			if (OB.the_ByteSegments_Count < 2)
			{
				throw new NetworkException(-6503);
			}
			if (m_sessionCtx.cryptoNeeded)
			{
				EncryptOraBuf(OB);
			}
			DataPacket.InitForSend(OB.m_buf, OB.m_curlen, m_sessionCtx);
			m_sessionCtx.m_transportAdapter.Send(OB);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				TraceOB(OB);
			}
		}

		private void EncryptOraBuf(OraBuf OB)
		{
			DataIntegrityAlgorithm dataIntegrityAlg = m_sessionCtx.m_ano.dataIntegrityAlg;
			EncryptionAlgorithm encryptionAlg = m_sessionCtx.encryptionAlg;
			int the_ByteSegments_Count = OB.the_ByteSegments_Count;
			int num = (m_sessionCtx.m_ano.foldedinkey ? 1 : 0);
			OraArraySegment oraArraySegment = OB.the_ByteSegments[the_ByteSegments_Count - 1];
			int num2 = 0;
			if (dataIntegrityAlg != null)
			{
				byte[] array = dataIntegrityAlg.compute(oraArraySegment.Array, oraArraySegment.Offset, oraArraySegment.Count);
				Buffer.BlockCopy(array, 0, oraArraySegment.Array, oraArraySegment.Count + oraArraySegment.Offset, array.Length);
				oraArraySegment.Count += array.Length;
				OB.m_curlen += array.Length;
			}
			if (encryptionAlg != null)
			{
				byte[] array2 = new byte[oraArraySegment.Count];
				Buffer.BlockCopy(oraArraySegment.Array, oraArraySegment.Offset, array2, 0, oraArraySegment.Count);
				byte[] array3 = m_sessionCtx.encryptionAlg.encrypt(array2);
				Buffer.BlockCopy(array3, 0, oraArraySegment.Array, oraArraySegment.Offset, array3.Length);
				num2 = array3.Length - oraArraySegment.Count;
				oraArraySegment.Count += num2;
				OB.m_curlen += num2;
			}
			if (dataIntegrityAlg != null || encryptionAlg != null)
			{
				oraArraySegment.Array[oraArraySegment.Count + oraArraySegment.Offset] = (byte)num;
				oraArraySegment.Count++;
				OB.m_curlen++;
			}
		}

		private void TraceOB(OraBuf OB)
		{
			OraArraySegment[] the_ByteSegments = OB.the_ByteSegments;
			int num = (ProviderConfig.m_bTraceLevelSecure ? 1 : OB.the_ByteSegments_Count);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				for (int i = 0; i < num; i++)
				{
					Trace.Write(OracleTraceLevel.Network, OracleTraceTag.BulkCopy, the_ByteSegments[i].Array, the_ByteSegments[i].Offset, the_ByteSegments[i].Count);
				}
			}
		}

		internal void Write(byte val)
		{
			m_oneByteBuffer[0] = val;
			Write(m_oneByteBuffer, 0, 1);
		}

		internal void Write(byte[] inputBuffer)
		{
			Write(inputBuffer, 0, inputBuffer.Length);
		}

		internal void Write(byte[] inputBuffer, int offset, int length)
		{
			int num = 0;
			int nSPDAFZER = DataPacket.NSPDAFZER;
			if (m_sessionCtx.m_onBreakReset)
			{
				throw new NetworkException(3111);
			}
			while (length > num)
			{
				num += m_dataPacket.PutDataInBuffer(inputBuffer, offset + num, length - num);
				if (m_dataPacket.m_isBufferFull)
				{
					nSPDAFZER = ((length > num) ? DataPacket.NSPDAFMOR : DataPacket.NSPDAFZER);
					m_dataPacket.Send(nSPDAFZER);
				}
			}
		}

		internal void Flush()
		{
			if (m_dataPacket.m_availableBytesToSend > 0)
			{
				m_dataPacket.Send(DataPacket.NSPDAFZER);
			}
		}

		internal void DiscardData()
		{
			m_dataPacket.Initialize();
		}
	}
}
